#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define STACK_SIZE (1024 * 1024)

static char child_stack[STACK_SIZE];
char *const child_args[] = {
    "/bin/bash",
    NULL,
};

int child_main(void *args)
{
    printf("在子进程中!\n");
    //执行echo $$
    //打印1
    //为了使执行top等命令只看到对应命名空间下的进程，还需要对文件系统挂载点进行隔离
    //mount -t proc proc /proc
    //由于目前还没有进行mount namespace的隔离，所以操作实际上已经影响了root namespace的文件系统。当退出新创建的namespace
    //时，再执行ps会报错，再次执行mount -t proc proc /proc即可修复
    sethostname("NewNameSpace", 12);
    execv(child_args[0], child_args);
    return 1;
}

int main()
{
    //内核为所有的PID namespace维护了一个树状结构，最顶层的是系统初创时创建的，被称为root namespace。它创建的新PID namespace
    //被称为child namespace，而原来的PID namespace就是新创建的PID namespace的parent namespace。通过这种方式，不同的PID namespace
    //会形成一个层级体系。所属的父节点可以看到子节点中的进程，并可以通过信号等方式对子节点中的进程产生影响。

    //将/proc设置为私有挂载，对其的操作就不会再影响父命名空间了
    printf("程序开始: \n");
    int child_pid = clone(child_main,
                          child_stack + STACK_SIZE,
                          CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWNET | SIGCHLD,
                          NULL);
    printf("errno: %s", strerror(errno));
    waitpid(child_pid, NULL, 0);
    printf("已退出\n");
    return 0;
}